package main

import (
	"fmt"
	"reflect"
)

type MyTest struct {
	Name string
	sex  int8
	Age  uint8
}

func (receiver MyTest) PrintInfo() {
	fmt.Printf("打印对象， 姓名：%v; 年龄：%v； 性别：%v", receiver.Name, receiver.Age, receiver.sex)
}
func (receiver MyTest) GetSex() (sex int8) {
	fmt.Println("我是GetSex")
	return receiver.sex
}

func (receiver MyTest) SetSex(sex int8) {
	fmt.Println("我是SetSex")
	receiver.sex = sex
}

func main() {
	mytest := MyTest{"张三", 1, 21}
	fmt.Println(mytest)
	testReflects(mytest)
	testReflectsValue(&mytest) // 设置值
	fmt.Println(mytest)

}

func testReflectsValue(mytest interface{}) {
	refType := reflect.TypeOf(mytest)
	refValue := reflect.ValueOf(mytest)
	fmt.Printf("从空接口提取：\nrefType：%T, %v \nrefValue: %T %v\n", refType, refType, refValue, refValue)
	// 设置结构体属性的值
	Name := refValue.Elem().FieldByName("Name")
	Name.SetString("李四")
}

func testReflects(mytest interface{}) {
	refType := reflect.TypeOf(mytest)
	refValue := reflect.ValueOf(mytest)
	fmt.Printf("从空接口提取：\nrefType：%T, %v \nrefValue: %T %v\n", refType, refType, refValue, refValue)
	// 获取结构体的属性字段
	for i := 0; i < refType.NumField(); i++ {
		f := refType.Field(i)
		fmt.Printf("field 类型：%T, %v,%v,%v\n", f, f.Name, f.Type, f.Type.Kind())
		switch f.Type.Kind() {
		case reflect.Int, reflect.Int64, reflect.Int32, reflect.Uint8, reflect.Int8:
			if refValue.Field(i).CanInt() {
				fmt.Println("a 的值是：", refValue.Field(i).Int())
			} else {
				fmt.Println("a 私有属性，不支持获取值")
			}
		case reflect.String:
			fmt.Println("a的值是：", refValue.Field(i).String())
		case reflect.Pointer:
			fmt.Println("a 是指针，", refValue.Field(i).Elem())
		default:
			fmt.Println("未找到a的类型")
		}
	}
	//Method 类型：reflect.Method, GetSex,func(main.MyTest) int8,0
	//Method 类型：reflect.Method, PrintInfo,func(main.MyTest),1
	//Method 类型：reflect.Method, SetSex,func(main.MyTest, int8),2
	// 获取结构体方法
	for i := 0; i < refType.NumMethod(); i++ {
		f := refType.Method(i)
		fmt.Printf("Method 类型：%T, %v,%v,%v\n", f, f.Name, f.Type, f.Index)
	}
	// 执行结构体方法
	GetSex := refValue.MethodByName("GetSex")
	r1 := GetSex.Call(nil) // r1 是[]reflect.Value类型的切片
	fmt.Printf("GetSex 执行： %T, %T,%v\n", r1, r1[0].Interface(), r1[0])
	PrintInfo := refValue.MethodByName("PrintInfo")
	r2 := PrintInfo.Call(nil)
	fmt.Printf("PrintInfo 执行： %T, %v\n", r2, len(r2))
	SetSex := refValue.MethodByName("SetSex")
	r3 := SetSex.Call([]reflect.Value{reflect.ValueOf(int8(0))})
	fmt.Printf("SetSex 执行： %T, %v\n", r3, len(r3))

}
